//Allocator with memory defragmentation for large data blocks 
// $Id: alloc_big.h 654 2011-02-21 17:07:19Z Oleg.Bulychov $
#pragma once

#include "src/heo/include/mem_util.h"

//__________________________________________________________________________________
//__________________________________________________________________________________
namespace mem_util
{
//__________________________________________________________________________________
struct TFloHeader
{
#if (MEM_DEBUG_MODE > 0)
    static const unsigned MAGIC_DWORD = 0xbeafc0c0u;
    unsigned      magic_;
#endif
    size_t        prev_offset_;
    size_t        block_size_;//== used_Size() + {reserved}
    size_t        data_size_;//:may used in containers!
    void**        back_ptr_;
#if (MEM_DEBUG_MODE > 0)
    unsigned      magic2_;
#endif
//.............................................................................
    explicit TFloHeader(size_t block_size, size_t data_size) NO_THROW_():
#if (MEM_DEBUG_MODE > 0)
        magic_(MAGIC_DWORD),
#endif
        //prev_offset_(),
        back_ptr_(),
        block_size_(block_size),
        data_size_(data_size)
#if (MEM_DEBUG_MODE > 0)
        , magic2_(MAGIC_DWORD)
#endif
    {}
//.............................................................................
    size_t used_Size() const NO_THROW_()
    {
        return ROUND2(data_size_ + sizeof(TFloHeader), MEM_GRANULARITY);
    }
//.............................................................................
    size_t avail_Size() const NO_THROW_()
    {
        return block_size_ - ROUND2(data_size_ + sizeof(TFloHeader), MEM_GRANULARITY);
    }
//.............................................................................
    size_t reserved_Size() const NO_THROW_()
    {
        return block_size_ - (data_size_ + sizeof(TFloHeader));
    }
//.............................................................................
    TFloHeader* prev_Ptr() const NO_THROW_()
    {
        return (TFloHeader*)((char*)this - prev_offset_);
    }
//.............................................................................
    void set_Prev(TFloHeader* prev) NO_THROW_()
    {
        prev_offset_ = (char*)this - (char*)prev;
    }
//.............................................................................
    TFloHeader* next_Ptr() const NO_THROW_()
    {
        return (TFloHeader*)((char*)this + block_size_);
    }
//.............................................................................
#if (MEM_DEBUG_MODE > 0)
    void check_Magic() const NO_THROW_()
    {
        ASSERT_(MAGIC_DWORD == magic_);
        ASSERT_(MAGIC_DWORD == magic2_);
    }
#endif
};
//__________________________________________________________________________________
//__________________________________________________________________________________
}//:mem_util
//__________________________________________________________________________________
//__________________________________________________________________________________
//__________________________________________________________________________________
class big_allocator
{
//.............................................................................
public:
//.............................................................................
    static bool construct(int nMaxThreads, size_t mb) NO_THROW_();
    static void destruct() NO_THROW_();
//.............................................................................
    static void** Alloc(size_t size, size_t reserved = 0,
                 bool bZeroInit = false) NO_THROW_();
//.............................................................................
    template<typename T>
    static T** AllocT(size_t count, size_t reservedCount = 0, bool bZeroInit = false) NO_THROW_()
    {
        return (T**)Alloc(count * sizeof(T), reservedCount * sizeof(T), bZeroInit);
    }
//.............................................................................
    static void Realloc(void* ptr, size_t size, size_t reserved = 0,
                 bool bZeroInit = false) NO_THROW_();
//.............................................................................
    template<typename T>
    static void ReallocT(T* ptr, size_t count, size_t reservedCount = 0,
        bool bZeroInit = false) NO_THROW_()
    {
        Realloc((void*)ptr, count * sizeof(T), reservedCount * sizeof(T), bZeroInit);
    }
//.............................................................................
    static void Free(void* ptr) NO_THROW_();
//.............................................................................
    template<typename T>
    static void FreeT(T** pt) NO_THROW_()
    {
        if (pt)
            Free((void*)*pt);
    }
//.............................................................................
    static size_t Get_Avail() NO_THROW_();//:doesn't take care of sizeof(TFloHeader)
//.............................................................................
    static void enter_Thread(int nRank) NO_THROW_();
    static void leave_Thread(int nRank) NO_THROW_();
//.............................................................................
    static void squeeze() NO_THROW_();
//.............................................................................
    static void report(std::ostream& os);
//.............................................................................
};

//EOF!
